package com.jintian.smart.kernel.orm.service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import com.jintian.smart.kernel.common.util.StringUtil;
import com.jintian.smart.kernel.core.orm.IBizTable;
import com.jintian.smart.kernel.core.orm.IBizTableLoader;
import org.beetl.sql.clazz.ClassDesc;
import org.beetl.sql.core.ConditionalSQLManager;
import org.beetl.sql.core.SQLManager;
import org.beetl.sql.core.SQLSource;
import org.beetl.sql.core.SqlId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

import com.fasterxml.jackson.databind.ObjectMapper;

public class DefaultBizTableLoader implements IBizTableLoader {

    @Autowired
    @Qualifier("sqlManager")
    private SQLManager sqlManager;

    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public String getPrimaryKey(Class clazz) {
        return sqlManager.getClassDesc(clazz).getIdAttr();
    }

    @Override
    public Map<String, List> loadBizTable(ClassLoader classLoader, List<? extends IBizTable> list, Map<String, Object> variables) {
        Map<String, List> ret = new HashMap<>();
        for (IBizTable table : list) {
            ret.putAll(this.loadTableData(classLoader, null, table, variables));
        }
        return ret;
    }

    private Map<String, List> loadTableData(ClassLoader clsLoader, IBizTable parent, IBizTable table, Map<String, Object> variables) {
        Map<String, List> ret = new HashMap<>();
        Class<?> clazz;
        try {
            clazz = clsLoader.loadClass(table.getEntityClass());
        } catch (ClassNotFoundException e) {
            throw new IllegalArgumentException(e.getMessage());
        }
        SQLManager currentSqlManager = sqlManager;
        if (sqlManager instanceof ConditionalSQLManager) {
            currentSqlManager = ((ConditionalSQLManager) sqlManager).decide(clazz);
        }
        ClassDesc classDesc = currentSqlManager.getClassDesc(clazz);
        String idAttr = classDesc.getIdAttr();
        List<?> listData = null;
        String sqlId = table.getSqlId();
        if (StringUtil.isNotBlank(sqlId)) {
            // SQLID 加载数据
            String namespace = sqlId.substring(0, sqlId.lastIndexOf("."));
            String id = sqlId.substring(sqlId.lastIndexOf(".") + 1);
            SqlId sql = SqlId.of(namespace, id);
            if (StringUtil.isNoneBlank(table.getCondition())) {
                SQLSource source = currentSqlManager.getSqlLoader().querySQL(sql);
                if (source == null) {
                    throw currentSqlManager.getSqlLoader().getException(sql);
                }
                StringBuffer sqlText = new StringBuffer("select * from (\n");
                sqlText.append(source.getTemplate()).append("\n)\n where ").append(table.getCondition());
                listData = currentSqlManager.execute(sqlText.toString(), clazz, variables);
            } else {
                listData = currentSqlManager.select(sql, clazz, variables);
            }
        } else {
            StringBuffer where = new StringBuffer();
            // 自定义条件
            if (StringUtil.isNoneBlank(table.getCondition())) {
                where.append(" and ").append(table.getCondition());
            }
            // 外键条件
            if (StringUtil.isNoneBlank(table.getForeignKey())) {
                String[] foreignKeys = table.getForeignKey().split(";");
                for (String foreignKey : foreignKeys) {
                    if (StringUtil.isBlank(foreignKey))
                        continue;
                    String[] keys = foreignKey.split("=");
                    String subAttr = keys[0].trim();
                    where.append(" and ").append(classDesc.getColByAttr(subAttr)).append("=#{").append(subAttr).append("}");
                }
            }

            String tableName = currentSqlManager.getNc().getTableName(clazz);
            String sql = "select * from " + tableName;
            if (where.length() > 0) {
                sql += " where " + where.substring(5);
            }
            listData = currentSqlManager.execute(sql, clazz, variables);
        }
        ret.put(table.getName().toUpperCase(), listData);
        // 加载子表数据
        if (listData != null && listData.size() > 0)
            for (int i = 0; i < listData.size(); i++) {
                Object data = listData.get(i);
                @SuppressWarnings("unchecked")
                Map<String, Object> dataMap = this.objectMapper.convertValue(data, HashMap.class);
                // 级联加载
                List<? extends IBizTable> subTables = table.getChildren();
                if (subTables == null || subTables.size() <= 0) {
                    continue;
                }
                for (IBizTable subTable : subTables) {
                    // 变量准备
                    Map<String, Object> subLoadVariables = new HashMap<>(variables);
                    if (StringUtil.isNoneBlank(subTable.getForeignKey())) {
                        String[] foreignKeys = subTable.getForeignKey().split(";");
                        for (String foreignKey : foreignKeys) {
                            if (StringUtil.isBlank(foreignKey))
                                continue;
                            Object parentValue = null;
                            String[] keys = foreignKey.split("=");
                            String parentAttr = keys.length > 1 ? keys[1].trim() : idAttr;
                            String subAttr = keys[0].trim();
                            parentValue = dataMap.get(parentAttr);
                            subLoadVariables.put(subAttr, parentValue);
                        }
                    } else {
                        dataMap.forEach((key, value) -> {
                            subLoadVariables.put(table.getName() + "." + key, value);
                        });
                    }
                    Map<String, List> subMap = this.loadTableData(clsLoader, table, subTable, subLoadVariables);
                    this.joinMap(subMap, ret);
                }
            }
        return ret;
    }

    @SuppressWarnings("unchecked")
    private void joinMap(Map<String, List> source, Map<String, List> target) {
        // 合并Map数据
        for (Entry<String, List> e : source.entrySet()) {
            List exitsList = target.get(e.getKey());
            if (exitsList == null) {
                target.put(e.getKey(), e.getValue());
            } else {
                exitsList.addAll(e.getValue());
            }
        }
    }
}
